'use strict';
/**
 * Module dependencies.
 */
var crypto = require('crypto');

module.exports = function(panes)
{
    /**
     * A Validation function for local strategy properties
     */
    var validateLocalStrategyProperty = function(property) {
        return ((this.provider !== 'local' && !this.updated) || property.length);
    };

    /**
     * A Validation function for local strategy password
     */
    var validateLocalStrategyPassword = function(password) {
        return (this.provider !== 'local' || (password && password.length > 6));
    };

    /**
     * validation function for local strategy phone number
     */
    var validateLocalStrategyPhone = function(phone) {
        return (this.provider !== 'local' || (phone && phone.length === 11));
    };

    /**
     * User Schema
     */
    return panes.model('User' , {
        firstName: {
            type: String,
            trim: true,
            default: '',
            validate: [validateLocalStrategyProperty, 'Please fill in your first name']
        },
        lastName: {
            type: String,
            trim: true,
            default: '',
            validate: [validateLocalStrategyProperty, 'Please fill in your last name']
        },
        displayName: {
            type: String,
            trim: true
        },
        telephone: {
            type: Number,
            trim: true,
            default: '00000000000',
            validate: [validateLocalStrategyPhone , ''],
            match: ['/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/' , '']
        },
        email: {
            type: String,
            trim: true,
            default: '',
            validate: [validateLocalStrategyProperty, 'Please fill in your email'],
            match: [/.+\@.+\..+/, 'Please fill a valid email address']
        },
        username: {
            type: String,
            unique: 'Username already exists',
            required: 'Please fill in a username',
            trim: true
        },
        password: {
            type: String,
            default: '',
            validate: [validateLocalStrategyPassword, 'Password should be longer']
        },
        salt: {
            type: String
        },
        provider: {
            type: String,
            required: 'Provider is required'
        },
        providerData: {},
        additionalProvidersData: {},
        roles: {
            type: [{
                type: String,
                enum: ['user', 'admin']
            }],
            default: ['user']
        },
        updated: {
            type: Date
        },
        created: {
            type: Date,
            default: Date.now
        },
        /* For reset password */
        resetPasswordToken: {
            type: String
        },
        resetPasswordExpires: {
            type: Date
        }
    } , {
        'pre': {
            /**
             * Hook a pre save method to hash the password
             */
            'save' : function(next)
            {
                if (this.password && this.password.length > 6) {
                    this.salt = crypto.randomBytes(16).toString('base64');
                    this.password = this.hashPassword(this.password);
                }
            next();
            }
        },
        'methods': {
            /**
             * Create instance method for hashing a password
             */
            'hashPassword': function(password) {
                if (this.salt && password) {
                    return crypto.pbkdf2Sync(password, new Buffer(this.salt, 'base64'), 10000, 64).toString('base64');
                } else {
                    return password;
                }
            },
            /**
             * Create instance method for authenticating user
             */
            'authenticate': function(password) {
                return this.password === this.hashPassword(password);
            }
        },
        'statics': {
            /**
             * Find possible not used username
             */
            findUniqueUsername: function(username, suffix, callback) {
                var _this = this;
                var possibleUsername = username + (suffix || '');

                _this.findOne({
                    username: possibleUsername
                }, function(err, user) {
                    if (!err) {
                        if (!user) {
                            callback(possibleUsername);
                        } else {
                            return _this.findUniqueUsername(username, (suffix || 0) + 1, callback);
                        }
                    } else {
                        callback(null);
                    }
                });
            }
        }
    });
};
